from django.shortcuts import render, redirect

from utils.views import LoginRequiredMinix, LoginRequiredJSONMixin, TransactionAtomicMixin

from django.views.generic import View

from django.core.urlresolvers import reverse

from django_redis import get_redis_connection

from goods.models import GoodsSKU

from users.models import Address

from django.http import JsonResponse

from orders.models import OrderInfo, OrderGoods

from django.utils import timezone

from django.db import transaction

from django.core.paginator import Paginator, EmptyPage


# Create your views here.
'''用户中心之全部订单页面的实现'''
class UserOrdersView(LoginRequiredMinix, View):

    def get(self, request, page):
        '''提供订单信息页面'''
        user = request.user

        # 查询所有订单
        orders = user.orderinfo_set.all().order_by('-create_time')

        for order in orders:
            # 给订单动态绑定：订单状态
            order.status_name = OrderInfo.ORDER_STATUS[order.status]
            # 给订单动态绑定：支付方式
            order.pay_method_name = OrderInfo.PAY_METHODS[order.pay_method]
            order.skus = []
            # 查询订单中所有商品
            order_skus = order.ordergoods_set.all()
            # 遍历订单中所有商品
            for order_sku in order_skus:
                sku = order_sku.sku
                sku.count = order_sku.count
                sku.amount = sku.price * sku.count
                order.skus.append(sku)

        '''分页设置'''
        page = int(page)

        try:
            paginator = Paginator(orders, 2)
            page_orders = paginator.page(page)

        except EmptyPage:
            # 如果传入的页面不存在,就默认给第一页
            page_orders = paginator.page(1)
            page = 1

        # 页数
        page_list = paginator.page_range

        context = {

            'orders': orders,
            'page': page,
            'page_list': page_list
        }


        return render(request, 'user_center_order.html', context)


'''订单提交'''
class CommitOrderView(LoginRequiredJSONMixin, TransactionAtomicMixin, View):
    # 由于使用ajax的json在前后端交互，所以LoginRequiredMixin，无法满足需求

    def post(self, request):
        '''后端的CommitOrderView视图，主要逻辑是保存订单信息，并把成功、错误通过json传给前端页面'''
        # 接受用户提交的订单信息,存储到OrderInfo和OrderGoods表中,跳转到全部订单页面

        # 获取参数：user,address_id,pay_method,sku_ids,count
        user = request.user
        address_id = request.POST.get('address_id')
        pay_method = request.POST.get('pay_method')
        sku_ids = request.POST.get('sku_ids')

        # print(11111111111)

        # 校验参数：all([address_id, pay_method, sku_ids])
        if not all([address_id, pay_method, sku_ids]):
            return JsonResponse({'code': 2, 'message': '参数不完整'})
        # print(222222222222)

        # 判断地址
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 3, 'message': '地址有误'})
        # print(33333333)

        # 判断支付方式
        if pay_method not in OrderInfo.PAY_METHOD:
            return JsonResponse({'code': 4, 'message': '支付方式有误'})
        # print(4444444444)


        redis_conn = get_redis_connection('default')

        # 截取出sku_ids列表
        sku_ids = sku_ids.split(',')
        # print(5555555555)

        # 定义临时变量
        total_count = 0
        total_sku_amount = 0

        # 生成order_id ---- strftime将时间转化成字符串, strptime将字符串转化为时间
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + str(user.id)


        '''在操作数据库前创建事务保存点'''
        save_point = transaction.savepoint()


        try:

            # 创建OrderInfo对象:order,用于存储用户,地址,支付方式
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_amount=0,
                trans_cost=10,
                pay_method=pay_method
            )


            # 遍历sku_ids
            for sku_id in sku_ids:

                '''每个订单有三次下单的机会'''
                for i in range(3):

                # 循环取出sku，判断商品是否存在
                    try:
                        sku = GoodsSKU.objects.get(id=sku_id)
                    except GoodsSKU.DoesNotExist:
                        return JsonResponse({'code': 5, 'message': '商品不存在'})

                    # 获取商品数量，判断库存 (redis)
                    sku_count = redis_conn.hget('cart_%s' % user.id, sku_id)

                    # 将sku_count转换类型
                    sku_count = int(sku_count)

                    # 判断是否超出库存
                    if sku_count > sku.stock:
                        return JsonResponse({'code': 6, 'message': '库存不足'})
                    # # 减少sku库存
                    # sku.stock -= sku_count
                    #
                    # # 增加sku销量
                    # sku.sales += sku_count
                    #
                    # sku.save()

                    '''使用乐观锁'''
                    origin_stock = sku.stock

                    new_stock = origin_stock - sku_count

                    new_sales = sku.sales + sku_count

                    # 更新库存和销量
                    result = GoodsSKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,sales=new_sales)

                    if 0 == result and i < 2:

                        # 还有机会,继续重新下单
                        continue
                    elif 0 == result and i == 2:
                        # 异常,回滚
                        transaction.savepoint_rollback(save_point)

                        return JsonResponse({'code': 8, 'message': '下单失败'})




                    # 保存订单商品数据OrderGoods(能执行到这里说明无异常)
                    # 先创建商品订单信息
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )


                    # 计算总数和总金额
                    total_count += sku_count

                    total_sku_amount += (sku_count * sku.price)

                    # 下单成功, 跳出循环
                    break

            # 修改订单信息里面的总数和总金额(OrderInfo)
            order.total_count = total_count

            order.total_amount = total_sku_amount + 10

            order.save()


        except Exception:
            '''出现任何异常都强制回滚'''

            transaction.savepoint_rollback(save_point)
            return JsonResponse({'code': 7, 'message': '下单失败'})


        '''没有异常就手动提交'''
        transaction.savepoint_commit(save_point)


        # 订单生成后删除购物车(hdel)
        # for sku_id in sku_ids:
        #     redis_conn.hdel('cart_%s' % user.id, sku_id)

        redis_conn.hdel('cart_%s' % user.id, *sku_ids)

        # 响应结果
        return JsonResponse({'code': 0, 'message': '下单成功'})





'''订单页面'''
# 点击《详情页》的《立即购买》可以进入该《订单确认页面》
# 点击《购物车》的《去结算》可以进入该《订单确认页面》
# 用户只有登陆时才可以查看订单页面
class PlaceOrdereView(LoginRequiredMinix, View):

    def post(self, request):
        # 判断用户是否登陆：LoginRequiredMixin

        # 获取参数：sku_ids, count
        sku_ids = request.POST.getlist('sku_ids')
        count = request.POST.get('count')

        # 校验sku_ids参数：not
        if not sku_ids:
            return redirect(reverse('goods: info'))

        redis_conn = get_redis_connection('default')

        user_id = request.user.id
        cart_dirt = redis_conn.hgetall('cart_%s' % user_id)

        # 临时变量
        skus = []
        total_count = 0
        total_sku_amount = 0
        trans_cost = 10

        # 校验count参数：用于区分用户从哪儿进入订单确认页面
        if count is None:
            # 如果是从购物车页面过来
            # 商品的数量从redis中获取

            for sku_id in sku_ids:
                # 查询商品数据
                try:
                    sku = GoodsSKU.objects.get(id=sku_id)
                except GoodsSKU.DoesNotExist:
                    return redirect(reverse('goods: info'))

                # redis中的sku_id,sku_count都是bytes类型
                sku_count = cart_dirt[sku_id.encode()]

                sku_count = int(sku_count)

                # 小计:
                amount = sku_count * sku.price

                # python是面向对象的动态语言
                sku.count = sku_count
                sku.amount = amount

                skus.append(sku)

                # 计算总数量和总金额
                total_count += sku_count

                total_sku_amount += amount




        else:
            # 如果是从详情页面过来
            for sku_id in sku_ids:

                # 查看商品数据
                try:
                    sku = GoodsSKU.objects.get(id=sku_id)
                except GoodsSKU.DoesNotExist:
                    return redirect(reverse('goods: index'))

                # 商品的数量从request中获取,并try校验
                try:
                    sku_count = int(count)
                except Exception:
                    return redirect(reverse('goods: detail', args=(sku_id,)))

                # 判断库存：立即购买没有判断库存
                if sku_count > sku.stock:
                    return redirect(reverse('goods: detail', args=(sku_id,)))

                # 计算商品总金额
                amount = sku_count * sku.price

                # 将商品的金额和数量封装到sku对象中
                sku.count = sku_count
                sku.amount = amount

                skus.append(sku)

                # 数量,金额求和
                total_count += sku_count

                total_sku_amount += amount

                # 立即购买时,需要将用户立即购买单额商品的信息,写入到redis.方便提交订单时读取count
                redis_conn.hset('cart_%s' % user_id, sku_id, sku_count)

        # 实付款//
        total_amount = total_sku_amount + trans_cost

        # 查询用户地址信息
        try:
            address = Address.objects.filter(user=request.user).latest('create_time')
        except Address.DoesNotExist:
            address = None

        # 构造上下文
        context = {
            'skus': skus,
            'total_count': total_count,
            'total_sku_amount': total_sku_amount,
            'trans_cost': trans_cost,
            'total_amount': total_amount,
            'address': address,
            'sku_ids': ','.join(sku_ids)
        }

        # 响应结果:html页面
        return render(request, 'place_order.html', context)
